const { Op } = require("sequelize");
const { Role: db, User, UsersRoles, RolesMenus } = require("../models");
const { NotFound, Conflict } = require("http-errors");
const { success } = require("../utils/response");

class RoleController {
  // 获取角色列表
  async getRoles(req, res, next) {
    try {
      const { name, code, createdAt, updatedAt, pageSize, pageNum, all } =
        req.query;
      const size = Math.abs(Number(pageSize)) || 15;
      const page = Math.abs(Number(pageNum)) || 1;
      const where = {};
      name &&
        (where["name"] = {
          [Op.like]: `%${name}%`,
        });
      code &&
        (where["code"] = {
          [Op.eq]: code,
        });
      createdAt &&
        (where["createdAt"] = {
          [Op.between]: createdAt.split(","),
        });
      updatedAt &&
        (where["updatedAt"] = {
          [Op.between]: updatedAt.split(","),
        });
      const condition = {
        order: [["updatedAt", "DESC"]],
        where,
      };
      if (!all) {
        condition["limit"] = size;
        condition["offset"] = (page - 1) * size;
      }
      const { count, rows } = await db.findAndCountAll(condition);

      success(
        res,
        "查询成功",
        all
          ? rows
          : {
              total: count,
              pageSize: size,
              pageNum: page,
              list: rows,
            }
      );
    } catch (error) {
      next(error);
    }
  }
  // 获取指定角色
  async getRole(req, res, next) {
    try {
      const id = req.params.id;
      const role = await db.findOne({
        where: { id },
      });
      if (!role) throw new NotFound("角色不存在");
      success(res, "查询成功", role);
    } catch (error) {
      next(error);
    }
  }
  // 添加角色
  async addRole(req, res, next) {
    try {
      const data = filterData(req.body);
      await db.create(data);
      success(res, "添加成功");
    } catch (error) {
      next(error);
    }
  }
  // 编辑角色
  async editRole(req, res, next) {
    try {
      const id = req.body.id;
      const role = await db.findOne({
        where: { id },
      });
      if (!role) throw new Conflict("角色不存在。");
      const data = filterData(req.body);
      // 更新数据
      await role.update(data);
      success(res, "编辑成功");
    } catch (error) {
      next(error);
    }
  }
  // 删除角色
  async delRole(req, res, next) {
    try {
      const ids = req.query.ids
        .split(",")
        .map((id) => Number(id))
        .filter(Boolean);
      await db.destroy({
        where: {
          id: ids,
        },
      });
      success(res, "删除成功");
    } catch (error) {
      next(error);
    }
  }
  /**
   * @description 获取当前角色下边的用户
   */
  async getUsersByRole(req, res, next) {
    try {
      const { id, pageNum, pageSize, keyword } = req.query;
      const size = Math.abs(Number(pageSize)) || 15;
      const page = Math.abs(Number(pageNum)) || 1;
      const where = keyword
        ? {
            [Op.or]: [
              {
                username: {
                  [Op.like]: `%${keyword}%`,
                },
              },
              {
                fullName: {
                  [Op.like]: `%${keyword}%`,
                },
              },
            ],
          }
        : {};

      const { users } = await db.findOne({
        where: { id },
        attributes: [],
        include: {
          model: User,
          as: "users",
          where,
          attributes: { exclude: ["password", "isDelete"] },
          through: {
            attributes: [],
          },
        },
      });

      success(res, "查询成功", {
        pageSize: size,
        pageNum: page,
        total: users.length,
        list: users.slice((page - 1) * size, size * page),
      });
    } catch (error) {
      next(error);
    }
  }

  /**
   * @description 获取当前角色下不包含的所有用户
   */
  async getUsersExclude(req, res, next) {
    const { id, pageNum, pageSize } = req.query;
    const size = Math.abs(Number(pageSize)) || 15;
    const page = Math.abs(Number(pageNum)) || 1;

    const userIds = (
      await UsersRoles.findAll({
        where: { roleId: id },
        attributes: ["userId"],
      })
    ).map((item) => item.toJSON().userId);

    const { count, rows } = await User.findAndCountAll({
      order: [["updatedAt", "DESC"]],
      offset: (page - 1) * size,
      attributes: { exclude: ["password", "isDelete"] },
      limit: size,
      where: {
        id: {
          [Op.notIn]: userIds,
        },
      },
    });
    success(res, "查询成功", {
      pageSize: size,
      pageNum: page,
      total: count,
      list: rows,
    });
  }

  /**
   * @description 给指定角色添加成员
   */
  async addUsersToRole(req, res, next) {
    try {
      await UsersRoles.bulkCreate(req.body, {
        updateOnDuplicate: ["userId", "roleId"],
      });
      success(res, "添加成功");
    } catch (error) {
      next(error);
    }
  }

  /**
   * @description 删除指定角色下边的成员
   */
  async delUserFormRole(req, res, next) {
    try {
      const { roleId, userId } = req.query;
      await UsersRoles.destroy({
        where: {
          userId,
          roleId,
        },
      });

      success(res, "删除成功");
    } catch (error) {
      next(error);
    }
  }

  // 授权，添加角色菜单关联
  async setAuth(req, res, next) {
    try {
      const { roleId, menuIds } = req.body;
      await RolesMenus.destroy({
        where: {
          roleId,
        },
      });

      await RolesMenus.bulkCreate(
        menuIds.map((menuId) => ({ roleId, menuId }))
      );

      success(res, "授权成功");
    } catch (error) {
      next(error);
    }
  }

  /**
   * 获取当前角色下已经授权的菜单
   */
  async getAuth(req, res, next) {
    try {
      const ret = await RolesMenus.findAll({
        where: { roleId: req.params.id },
      });

      success(
        res,
        "查询成功",
        ret.map((item) => item.toJSON().menuId)
      );
    } catch (error) {
      next(error);
    }
  }
}

// 数据过滤
function filterData(data) {
  const nowData = {
    name: data.name,
    code: data.code,
    remark: data.remark,
    status: data.status,
  };

  return Object.fromEntries(
    Object.entries(nowData).filter(
      (item) => item[1] !== "" && item[1] !== void 0
    )
  );
}

module.exports = new RoleController();
